#include "network/buffered_fd.hpp"

#include "base/assert.hpp"
#include "base/log.hpp"
#include "event/fd_event.hpp"
#include "event/loop.hpp"

#include <cstring>

namespace ibox::network {

using namespace std::placeholders;
using namespace ibox::event;

BufferedFd::BufferedFd(event::EpollLoop *loop)
    : m_loop{loop}, m_send_buff{0}, m_recv_buff{0} {}

BufferedFd::~BufferedFd() {
    if (m_state == State::Running) {
        disable();
    }

    // if (m_write_event) {
    //     delete m_write_event;
    // }
    // if (m_read_event) {
    //     delete m_read_event;
    // }
}

bool BufferedFd::initialize(Fd &fd, uint32_t events) {
    if (fd.is_null()) {
        LOG_WARNING("fd is null");
        return false;
    }

    if (events == 0) {
        LOG_WARNING("events == 0");
        return false;
    }

    if (m_state != State::Empty) {
        LOG_WARNING("can't reinitialize");
        return false;
    }

    m_fd = fd;
    m_fd.set_nonblock(true);

    // if (m_write_event) {
    //     delete m_write_event;
    // }
    // if (m_read_event) {
    //     delete m_read_event;
    // }

    if (static_cast<bool>(events & ReadOnly)) {
        m_read_event = std::make_unique<EpollFdEvent>(
            m_loop, m_fd.get(), FdEvent::ReadEvent, Event::Mode::Forever);
        m_read_event->set_callback([&](uint32_t s) { on_read_callback(s); });
    }

    if (static_cast<bool>(events & WriteOnly)) {
        m_write_event = std::make_unique<EpollFdEvent>(
            m_loop, m_fd.get(), FdEvent::WriteEvent, Event::Mode::Forever);
        m_write_event->set_callback([&](uint32_t s) { on_write_callback(s); });
    }

    m_state = State::Inited;

    return true;
}

void BufferedFd::set_receive_callback(ReceiveCallback cb, size_t threshold) {
    m_receive_cb = std::move(cb);
    m_receive_threshold = threshold;
}

bool BufferedFd::enable() {
    if (m_state == State::Running) {
        return true;
    }

    if (m_state != State::Inited) {
        LOG_WARNING("please initialize() first");
        return false;
    }

    if (m_read_event != nullptr) {
        m_read_event->enable();
    }

    m_state = State::Running;

    return true;
}

bool BufferedFd::disable() {
    if (m_state == State::Inited) {
        return true;
    }

    if (m_state != State::Running) {
        LOG_WARNING("please initialize() first");
        return false;
    }

    if (m_read_event != nullptr) {
        m_read_event->disable();
    }

    if (m_write_event != nullptr) {
        m_write_event->disable();
    }

    m_state = State::Inited;

    return true;
}

bool BufferedFd::send(const void *data_ptr, size_t data_size) {
    if (m_write_event == nullptr) {
        LOG_WARNING("send is disabled");
        return false;
    }

    // 如果当前没有 enable() 或者发送缓冲区中还有没有发送完成的数据
    if ((m_state != State::Running) || (m_send_buff.readable_size() > 0)) {
        // 则新的数据就直接放到发送缓冲区
        m_send_buff.append(data_ptr, data_size);
    } else {
        // 否则尝试发送
        ssize_t wsize = m_fd.write(data_ptr, data_size);
        if (wsize >= 0) { // 如果发送正常
            // 如果没有发送完，还有剩余的数据
            if (static_cast<size_t>(wsize) < data_size) {
                // 则将剩余的数据放入到缓冲区
                const uint8_t *p_remain
                    = static_cast<const uint8_t *>(data_ptr) + wsize;
                m_send_buff.append(p_remain, (data_size - wsize));
                m_write_event->enable(); // 等待可写事件
            }
        } else {                   // 否则就是出了错
            if (errno == EAGAIN) { // 文件操作繁忙
                m_send_buff.append(data_ptr, data_size);
                m_write_event->enable(); // 等待可写事件
            } else {
                LOG_WARNING("send fail, drop data. errno:%d, %s",
                            errno,
                            strerror(errno));
                // TODO
            }
        }
    }

    return true;
}

void BufferedFd::shrink_recv_buffer() { m_recv_buff.shrink(); }

void BufferedFd::shrink_send_buffer() { m_send_buff.shrink(); }

void BufferedFd::on_read_callback(uint32_t) {
    struct iovec rbuf[2];
    char extbuf[1024]; // 扩展存储空间

    size_t writable_size = m_recv_buff.writable_size();

    // 优先将数据读入到 m_recv_buff 中去，如果它装不下就再存到 extbuff 中
    rbuf[0].iov_base = m_recv_buff.writable_begin();
    rbuf[0].iov_len = writable_size;
    rbuf[1].iov_base = extbuf;
    rbuf[1].iov_len = sizeof(extbuf);

    ssize_t rsize = m_fd.readv(rbuf, 2);
    if (rsize > 0) { // 读到了数据
        do {
            if (static_cast<size_t>(rsize) > writable_size) {
                // 如果实际读出的数据比 m_recv_buff
                // 的可写区还大，说明有部分数据是写到了 extbuf 中去了
                m_recv_buff.has_written(writable_size);
                size_t remain_size
                    = rsize - writable_size; // 计算 extbuf 中的数据大小
                m_recv_buff.append(extbuf, remain_size);
            } else {
                m_recv_buff.has_written(rsize);
            }

            // 继续读，直到 rsize == 0，表示读完为止
            writable_size = m_recv_buff.writable_size();
            rbuf[0].iov_base = m_recv_buff.writable_begin();
            rbuf[0].iov_len = writable_size;
        } while ((rsize = m_fd.readv(rbuf, 2)) > 0);

        // 如果有绑定接收者，则应将数据直接转发给接收者
        if (m_receiver != nullptr) {
            m_receiver->send(m_recv_buff.readable_begin(),
                             m_recv_buff.readable_size());
            m_recv_buff.has_readall();

            // 否则, 调用receive回调函数
        } else if (m_recv_buff.readable_size() >= m_receive_threshold) {
            if (m_receive_cb) {
                m_receive_cb(m_recv_buff);
            } else {
                LOG_WARNING("m_receive_cb is not set");
                m_recv_buff.has_readall(); // 丢弃数据，防止堆积
            }
        }

    } else if (rsize == 0) { // 读到0字节数据，说明m_fd已不可读了
        m_read_event->disable();
        if (m_read_zero_cb) {
            m_read_zero_cb();
        }
    } else { // 读出错了
        if (errno != EAGAIN) {
            if (m_error_cb) {
                m_error_cb(errno);
            } else {
                LOG_WARNING("read error, rsize:%d, errno:%d, %s",
                            rsize,
                            errno,
                            strerror(errno));
            }
        }
    }
}

void BufferedFd::on_write_callback(uint32_t) {
    // 如果发送缓冲中已无数据要发送了，那就关闭可写事件
    if (m_send_buff.readable_size() == 0) {
        m_write_event->disable();

        if (m_send_complete_cb) {
            m_send_complete_cb();
        }
        return;
    }

    // 下面是有数据要发送的
    ssize_t wsize
        = m_fd.write(m_send_buff.readable_begin(), m_send_buff.readable_size());
    if (wsize >= 0) {
        m_send_buff.has_read(wsize);
    } else {
        if (m_error_cb) {
            m_error_cb(errno);
        } else {
            LOG_WARNING("write error, wsize:%d, errno:%d, %s",
                        wsize,
                        errno,
                        strerror(errno));
        }
    }
}

} // namespace ibox::network
